<template>
    <el-card>
        <el-form label-width="120px" :model="spuInfo" :rules="rules" ref="spuFormRef">
            <el-form-item label="SPU名称" prop="spuName">
                <el-input placeholder="SPU名称" v-model="spuInfo.spuName" />
            </el-form-item>
            <el-form-item label="品牌" prop="tmId">
                <el-select placeholder="请选择" style="width: 300px" v-model="spuInfo.tmId">
                    <el-option v-for="item in trademarkList" :key="item.id" :value="item.tmName"></el-option>
                </el-select>
            </el-form-item>
            <el-form-item label="SPU描述" prop="description">
                <el-input :rows="4" type="textarea" placeholder="SPU描述" v-model="spuInfo.description" />
            </el-form-item>
            <el-form-item label="SPU图片" prop="spuImageList">
                <el-upload v-model:file-list="spuInfo.spuImageList" :action="`${BASE_URL}/admin/product/upload`"
                    list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove"
                    success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
                    <el-icon>
                        <Plus />
                    </el-icon>
                </el-upload>

                <el-dialog v-model="dialogVisible">
                    <img w-full :src="dialogImageUrl" />
                </el-dialog>
            </el-form-item>
            <el-form-item label="销售属性" prop="spuSaleAttrList">
                <el-select :placeholder="`还有${filterBaseSaleAttrList.length}项未选择`" style="width: 200px"
                    v-model="spuInfo.spuSaleAttr">
                    <el-option v-for="item in filterBaseSaleAttrList" :key="item.id" :value="item.name"></el-option>
                </el-select>
                <el-button type="primary" :icon="Plus" @click="addSale">添加销售属性</el-button>


                <el-table border style="margin:20px 0" :data="spuInfo.spuSaleAttrList">
                    <el-table-column label="序号" type="index" width="80px" align="center" />
                    <el-table-column label="属性名" prop="saleAttrName" width="100px" />
                    <el-table-column label="属性值名称列表">
                        <template v-slot="{ row }">
                            <el-tag type="success" v-for="item in row.spuSaleAttrValueList" :key="item"
                                style="margin-right:5px" @close="handleClose(row, item)" :disable-transitions="false"
                                closable>
                                {{ item.saleAttrValueName }}
                            </el-tag>
                            <el-input v-if="row.inputVisible" v-model="SaleValue" ref="inputRef"
                                @blur="addSaleValue(row)" @keyup.enter="addSaleValue(row)" />
                            <el-button v-else @click="addValue(row)">+ New</el-button>
                        </template>
                    </el-table-column>
                    <el-table-column label="操作">
                        <template v-slot="{ $index }">
                            <el-button type="danger" size="small" :icon="Delete" title="删除"
                                @click="deleteSale($index)" />
                        </template>
                    </el-table-column>
                </el-table>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="submitSpuForm(spuFormRef)">保存</el-button>
                <el-button @click="emits('setShowStatus', 1)">取消</el-button>
            </el-form-item>
        </el-form>
    </el-card>
</template>

<!-- 
    添加/修改
    通过传入的参数来确定是添加还是修改操作，添加是没有数据的
    创建表单数据双向绑定，品牌数据和销售需要发送请求将需要渲染的数据请求回来
    销售属性有个倒计数的样式，需要使用计算属性处理数据
        每次选中的数据都添加到spuSaleAttrList中，如果spuSaleAttrList中有数据filterBaseSaleAttrList中则需要过滤掉
    
    添加销售属性，将属性添加到数组内，使用这个数组渲染下面的table列表，列表中还有一个列表数组，通过值来判断是input输入还是tag展示

    上传图片，四个函数
        上传之前：beforeAvatarUpload：可以在此对图片做一些校验，比如图片格式大小
        上传图片：handlePictureCardPreview：
        上传之后：handleAvatarSuccess：
        删除图片：handleRemove：删除的处理程序

    保存
        写的校验规则只能浅层校验，对于spuSaleAttrValueList这种并不能检测到，所以在保存的时候需要对内部的数组进行遍历判断是否有值
        图片数组在保存时直接将结果添加进去了，在提交之前要修改数据格式


最终需要提交的数据
 -->

<!-- {
    "category3Id": 0,  // 三级id
    "description": "string", // 描述
    spuSaleAttr：string  // 选中的属性
    "spuImageList": [  // 存储图片的数组
        {
            "imgName": "string",
            "imgUrl": "string",
            "spuId": 0,
        }
    ],
    "spuName": "string", // 名称
    "spuSaleAttrList": [  // 基本销售属性
        {
            "baseSaleAttrId": 0,
            "saleAttrName": "string",
            "spuId": 0,
            "spuSaleAttrValueList": [
                {
                    "baseSaleAttrId": 0,
                    "isChecked": "string",
                    "saleAttrName": "string",
                    "saleAttrValueName": "string",
                    "spuId": 0,
                }
            ],
        }
    ],
    "tmId": 0 //spu品牌
} -->

<script lang="ts">
export default {
    name: 'SpuForm'
}
</script>
<script lang="ts" setup>
import { Plus, Delete } from '@element-plus/icons-vue'
import type { UploadProps, UploadFile, UploadFiles, FormInstance, FormRules } from 'element-plus'
import { ElInput, ElMessage } from 'element-plus'
import { ref, reactive, onMounted, computed, nextTick } from 'vue'
import { reqGetSpuBaseList, reqGetTrademarkList, reqSaveSpuInfo, reqGetSpuImageList, reqGetSpuSaleAttrList, reqUpdateSpuInfo } from '@/api/product/spu'
import type { SpuSaleAttrList, spuInfoModel, baseSaleListModel, trademarkModel } from '@/api/product/model/spu'
import { useGetCategoryStore } from '@/stores/categoryList'

const categoryStore = useGetCategoryStore()
// 接收自定义事件
const emits = defineEmits(['setShowStatus'])
const props = defineProps(['currentSpu'])


// 图片相关
const dialogImageUrl = ref<string>('')
const dialogVisible = ref(false)

// 上传图片地址，会从.env.development中加载

const BASE_URL = import.meta.env.VITE_API_URL

// 定义数据
let spuInfo = reactive<spuInfoModel>({
    category3Id: categoryStore.category3Id,
    tmId: '',
    spuName: '',
    description: '',
    spuSaleAttr: '',
    spuSaleAttrList: [],
    spuImageList: [],
    ...props.currentSpu
})

// 准备两个数组存储数据，品牌数据，基本属性列表
const trademarkList = ref<trademarkModel>([])
const baseSaleAttrList = ref<baseSaleListModel>([])
const SaleValue = ref<string>('')
const inputRef = ref<InstanceType<typeof ElInput>>()
const formSize = ref('default')
const spuFormRef = ref<FormInstance>()

// 校验规则
const rules = reactive<FormRules>({
    spuName: [
        { required: true, message: '请输入SPU名称', trigger: 'blur' },
        { min: 1, max: 10, message: 'SPU名称必须在1-10个字符之间', trigger: 'blur' }
    ],
    tmId: [{ required: true, message: '请选择SPU品牌', trigger: 'change' }],
    description: [{ required: true, message: '请输入SPU描述', trigger: 'blur' }],
    spuImageList: [{ required: true, message: '请选择一张图片', type: 'array', trigger: 'change' }],
    spuSaleAttrList: [{ required: true, message: '请至少添加一个属性', type: 'array', trigger: 'click' }]
})

// 删除图片
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
    // console.log(uploadFiles);
    spuInfo.spuImageList = uploadFiles
}
// 添加图片
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
    dialogImageUrl.value = uploadFile.url!
    dialogVisible.value = true
}
// 上传之前校验
const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => {
    const imgTypes = ['image/jpeg', 'image/jpg', 'image/png']
    if (!imgTypes.includes(rawFile.type)) {
        ElMessage.error('上传的图片必须是JPG/JPEG/PNG格式，请重试')
        return false
    } else if (rawFile.size / 1024 / 1024 > 2) {
        ElMessage.error('图片最大不能超过2M,请重试！')
        return false
    }
    return true
}
// 上传成功之后
const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
    spuInfo.spuImageList.push({
        imgName: uploadFile.name,
        imgUrl: response.data
    })
    // spuInfo.spuImageList = uploadFile
    spuFormRef.value!.clearValidate(['spuImageList'])
}

// 在挂载后请求品牌数据，基本属性列表
onMounted(async () => {
    try {
        let promises = [reqGetSpuBaseList(), reqGetTrademarkList()]
        if (spuInfo.id) {
            promises = promises.concat([reqGetSpuImageList(spuInfo.id), reqGetSpuSaleAttrList(spuInfo.id)])
        }
        const [a, b, c, d] = await Promise.all(promises)
        baseSaleAttrList.value = a
        trademarkList.value = b
        // console.log('c', c);
        // console.log('d', d);
        if (c && d) {
            spuInfo.spuImageList = c.map((item: any) => {
                return {
                    ...item,
                    name: item.imgName,
                    url: item.imgUrl
                }
            })
            spuInfo.spuSaleAttrList = d
        }


    } catch (error) {
        console.log(error);

    }
})

// 使用计算属性处理数据,
const filterBaseSaleAttrList = computed(() => {
    return baseSaleAttrList.value.filter(item => {
        return !spuInfo.spuSaleAttrList.find(value => item.name === value.saleAttrName)
    })
})

// 添加销售属性
const addSale = () => {
    // 做一个判空操作
    const spuSaleAttrList = spuInfo.spuSaleAttrList
    if (spuSaleAttrList.length && !spuSaleAttrList.some(item => item.spuSaleAttrValueList.length)) {
        ElMessage.error('有属性值为空，请添加')
        return
    }
    if (!spuInfo.spuSaleAttr) return
    const id = baseSaleAttrList.value.find(item => item.name == spuInfo.spuSaleAttr).id

    spuInfo.spuSaleAttrList.push({
        baseSaleAttrId: id,
        inputVisible: false, // 给当前行对象添加一个属性，用于控制按钮和输入框的显示
        saleAttrName: spuInfo.spuSaleAttr, // 属性名 颜色 版本  尺寸
        spuSaleAttrValueList: [] // 当前属性名对应的那些详细的属性值
    })
    // 清空输入框的值
    spuInfo.spuSaleAttr = ''

    // 清空校验规则
    spuFormRef.value!.clearValidate(['spuSaleAttrList'])
}
// 添加属性值,点击之后改变为输入框，并且自动获取焦点
const addValue = (row: SpuSaleAttrList) => {
    row.inputVisible = true
    nextTick(() => {
        inputRef.value!.focus()
    })

}

// 保存输入框的值
const addSaleValue = (row: SpuSaleAttrList) => {
    // 如果没有值不保存，如果有值查找是否重复，重复不保存
    if (SaleValue.value) {
        const spuSaleAttrValueList = row.spuSaleAttrValueList
        if (spuSaleAttrValueList.length && spuSaleAttrValueList.find(item => item.saleAttrValueName == SaleValue.value)) {
            ElMessage.error('属性值不能重复，请更换……')
            row.inputVisible = false
            SaleValue.value = ''
            return
        }
        const id = baseSaleAttrList.value.find(item => item.name === row.saleAttrName).id

        row.spuSaleAttrValueList.push({
            baseSaleAttrId: id,
            saleAttrName: row.saleAttrName,
            saleAttrValueName: SaleValue.value
        })
    }
    row.inputVisible = false
    SaleValue.value = ''
    /*   "spuSaleAttrValueList": [
                {
                    "baseSaleAttrId": 0,
                    "isChecked": "string",
                    "saleAttrName": "string",
                    "saleAttrValueName": "string",
                    "spuId": 0,
                }
            ],
             */
}

// 删除属性值
const deleteSale = (index: number) => {
    spuInfo.spuSaleAttrList.splice(index, 1)

}
// 删除tag
const handleClose = (row: SpuSaleAttrList, tag: any) => {

    row.spuSaleAttrValueList.splice(row.spuSaleAttrValueList.indexOf(tag), 1)
}

// 保存
const submitSpuForm = async (formEl: FormInstance | undefined) => {
    if (!formEl) return
    await formEl.validate(async (valid, fields) => {
        if (valid) {
            const spuSaleAttrList = spuInfo.spuSaleAttrList
            if (spuSaleAttrList.length && !spuSaleAttrList.every(item => item.spuSaleAttrValueList.length)) {
                ElMessage.error('有属性值为空，请添加……')
                return
            }

            spuInfo.spuImageList = spuInfo.spuImageList.map(item => {
                return {
                    imgName: item.name,
                    imgUrl: item.response?.data || item.url
                }
            })
            if (spuInfo.id) {
                await reqUpdateSpuInfo(spuInfo)
                ElMessage.success('修改SPU成功……')
            } else {
                await reqSaveSpuInfo(spuInfo)
                ElMessage.success('添加SPU成功……')
            }
            emits('setShowStatus', 1)

        } else {
            console.log('error submit!', fields)
        }
    })
}
</script>

<style>
</style>